/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import junit.framework.TestCase;

/**
 * Performs Validation Test for url validations.
 *
 * @version $Revision: 1128446 $ $Date: 2011-05-27 13:29:27 -0700 (Fri, 27 May 2011) $
 */
public class UrlValidatorTest extends TestCase {

   private boolean printStatus = false;
   private boolean printIndex = false;//print index that indicates current scheme,host,port,path, query test were using.
   int[] testPartsIndex = {0, 0, 0, 0, 0};


   public UrlValidatorTest(String testName) {
      super(testName);
   }
   
   //---------------- Test data for individual url parts ----------------
   ResultPair[] testScheme = {new ResultPair("http", true),
                            new ResultPair("ftp", false),
                            new ResultPair("httpd", false),
                            new ResultPair("telnet", false)};

   public void testManualTest()
   {
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	   System.out.println(urlVal.isValid("http://www.google.com") + " true 1");
	   System.out.println(urlVal.isValid("3ht://www.google.com") + " false 2");
	   System.out.println(urlVal.isValid("h3t://www.google.com") + " true 3");
	   System.out.println(urlVal.isValid("http:/www.google.com") + " false 4");
	   System.out.println(urlVal.isValid("http/www.google.com") + " false 5");
	   System.out.println(urlVal.isValid("://ww.google.com") + " false 6");
	   System.out.println(urlVal.isValid("http://www.google.com:80") + " true 7");
	   System.out.println(urlVal.isValid("http://0.0.0.0") + " true 8");
	   System.out.println(urlVal.isValid("http://1.2.3.4.5") + " false 9");
	   System.out.println(urlVal.isValid("http://255.255.255.255") + " true 10");
	   System.out.println(urlVal.isValid("http://255.255.255.256") + " false 11");
	   System.out.println(urlVal.isValid(".1.2.3.4") + " false 12");
	   System.out.println(urlVal.isValid("http://go.cc") + " true 13");
	   System.out.println(urlVal.isValid("http://go.1aa") + " false 14");
	   System.out.println(urlVal.isValid("http://www.google.com:80") + " true 15");
	   System.out.println(urlVal.isValid("http://www.google.com:-1") + " false 16");
	   System.out.println(urlVal.isValid("http://www.google.com/test1") + " true 17");
	   System.out.println(urlVal.isValid("http://www.google.com/$23") + " true 18");
	   System.out.println(urlVal.isValid("http://www.google.com/..//file") + " false 19");
	   System.out.println(urlVal.isValid("http://www.google.com?action=view") + " true 20");
	   System.out.println(urlVal.isValid("http://www.google.com?action=edit&mode=up") + " true 21");	   
   }
 
   //Partition Tests
   //I have two partition testing cases set up in the following two test cases
   //Please read the comment on the partition test for clarifications
   
   //Partition: IP Addresses
   //Description:   This test implements the first chosen partitioning for the isValid method
   //				I will test several IP Address valid and invalid to see how the method
   //				handles them.
   public void testYourFirstPartition()
   {
	   //Initialization
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	   boolean shouldBeTrue = true;
	   boolean shouldBeFalse = false;

	   System.out.println("Start Input Partition Test Part 1 - IP Addresses");
	   
	   //Valid IP Addresses
	   System.out.print("Google's IP Address returned ");
	   assertTrue(urlVal.isValid("http://173.194.33.7") == shouldBeTrue);
	   System.out.println("as valid. - Passed");
	   
	   System.out.print("Pandora's IP Address returned ");
	   assertTrue(urlVal.isValid("http://208.85.40.50") == shouldBeTrue);
	   System.out.println("as valid. - Passed");
	   
	   System.out.print("Oregon State's IP Address returned ");
	   assertTrue(urlVal.isValid("http://128.193.4.112") == shouldBeTrue);
	   System.out.println("as valid. - Passed");	   
	   
	   //Invalid IP Addresses
	   System.out.print("Invalid IP address 1.2.3.4.5 returned ");
	   assertTrue(urlVal.isValid("http://1.2.3.4.5") == shouldBeFalse);
	   System.out.println("as invalid. - Passed");
	   
	   System.out.print("Invalid IP address -1.-2.-3.-4.-5 returned ");
	   assertTrue(urlVal.isValid("http://-1.-2.-3.-4.-5") == shouldBeFalse);
	   System.out.println("as invalid. - Passed");
	     
	   System.out.print("Invalid IP address 1.2.3 returned ");
	   assertTrue(urlVal.isValid("http://1.2.3") == shouldBeFalse);
	   System.out.println("as invalid. - Passed");
	   
	   System.out.print("Invalid Google IP address http://.173.194.33.7 returned ");
	   assertTrue(urlVal.isValid("http://.173.194.33.7") == shouldBeFalse);
	   System.out.println("as invalid. - Passed");
	   
	   System.out.print("Invalid Google IP address http://173.194.33.7. returned ");
	   assertTrue(urlVal.isValid("http://173.194.33.7.") == shouldBeFalse);
	   System.out.println("as invalid. - Passed");
	   
	   System.out.print("Invalid Google IP address 173.194.33.7. returned ");
	   assertTrue(urlVal.isValid("173.194.33.7.") == shouldBeFalse);
	   System.out.println("as invalid. - Passed");
	   
	   System.out.print("Invalid IP address 256.256.256.256 returned ");
	   assertTrue(urlVal.isValid("http://256.256.256.256") == shouldBeFalse);			//BUG
	   System.out.println("as invalid. - Passed");      
   }
   
   //Partition: Regular URL Expressions
   //Description: This test implements the second chosen partitioning for the isValid method
   //  			  I will test several URL regular expressions both valid and invalid to see how
   //			  the method handles them.
   
   public void testYourSecondPartition(){
	   
	   //Initialization
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	   boolean shouldBeTrue = true;
	   boolean shouldBeFalse = false;

	   System.out.println("Start Input Partition Test Part 2 - URLs");
	   
	   //Valid URLs
	   System.out.print("Google URL returned ");
	   assertTrue(urlVal.isValid("http://Google.com") == shouldBeTrue);
	   System.out.println("as valid. - Passed");
	   
	   System.out.print("Oregon State's URL returned ");
	   assertTrue(urlVal.isValid("http://OregonState.edu") == shouldBeTrue);
	   System.out.println("as valid. - Passed");
	      
	   //Invalid URLs
	   System.out.print("Empty URL returned ");
	   assertTrue(urlVal.isValid("http://") == shouldBeFalse);
	   System.out.println("as invalid. - Passed");
	   
	   System.out.print("Invalid httppp:/Google.com URL returned ");
	   assertTrue(urlVal.isValid("httppp:/Google.edu") == shouldBeFalse);		
	   System.out.println("as invalid. - Passed");
	      
	   System.out.print("Invalid http://Google.edu URL returned ");
	   assertTrue(urlVal.isValid("http://Google.edu") == shouldBeFalse);		//BUG
	   System.out.println("as invalid. - Passed");
	   
	   
   }
   
   ResultPair[] testUrlScheme = {new ResultPair("http://", true),
           new ResultPair("http:/", false),
           new ResultPair("http:", false),
           new ResultPair("http/", false),};
   
   ResultPair[] testUrlAuthority = {new ResultPair("www.google.com", true),
           new ResultPair("oregonstate.edu", true),
           new ResultPair("twitter.com", true),
           new ResultPair("0.0.0.0", true),
           new ResultPair("255.255.255.255", true),
           new ResultPair("256.256.256.256", false),
           new ResultPair("", false)
   };

   ResultPair[] testUrlPort = {new ResultPair(":80", true),
           new ResultPair(":65535", true),
           new ResultPair(":0", true),
           new ResultPair("", true),
           new ResultPair(":-1", false),
           new ResultPair(":65636", true),
           new ResultPair(":65a", false)
};
ResultPair[] testPath = {new ResultPair("/test1", true),
        new ResultPair("/t123", true),
        new ResultPair("/$23", true),
        new ResultPair("/..", false),
        new ResultPair("/../", false),
        new ResultPair("/test1/", true),
        new ResultPair("", true),
        new ResultPair("/test1/file", true),
        new ResultPair("/..//file", false),
        new ResultPair("/test1//file", false)
};
//Test allow2slash, noFragment
ResultPair[] testUrlPathOptions = {new ResultPair("/test1", true),
                  new ResultPair("/t123", true),
                  new ResultPair("/$23", true),
                  new ResultPair("/..", false),
                  new ResultPair("/../", false),
                  new ResultPair("/test1/", true),
                  new ResultPair("/#", false),
                  new ResultPair("", true),
                  new ResultPair("/test1/file", true),
                  new ResultPair("/t123/file", true),
                  new ResultPair("/$23/file", true),
                  new ResultPair("/../file", false),
                  new ResultPair("/..//file", false),
                  new ResultPair("/test1//file", true),
                  new ResultPair("/#/file", false)
};

ResultPair[] testUrlQuery = {new ResultPair("?action=view", true),
            new ResultPair("?action=edit&mode=up", true),
            new ResultPair("", true)
};

Object[] testUrlParts = {testUrlScheme, testUrlAuthority, testUrlPort, testPath, testUrlQuery};
Object[] testUrlPartsOptions = {testUrlScheme, testUrlAuthority, testUrlPort, testUrlPathOptions, testUrlQuery};

protected void setUp() {
    for (int index = 0; index < testPartsIndex.length - 1; index++) {
       testPartsIndex[index] = 0;
    }
 }
   
   public void testIsValid() {
       testIsValid(testUrlParts, UrlValidator.ALLOW_ALL_SCHEMES);
       setUp();
  }

static boolean incrementTestPartsIndex(int[] testPartsIndex, Object[] testParts) {
     boolean carry = true;  //add 1 to lowest order part.
     boolean maxIndex = true;
     for (int testPartsIndexIndex = testPartsIndex.length - 1; testPartsIndexIndex >= 0; --testPartsIndexIndex) {
        int index = testPartsIndex[testPartsIndexIndex];
        ResultPair[] part = (ResultPair[]) testParts[testPartsIndexIndex];
        if (carry) {
           if (index < part.length - 1) {
              index++;
              testPartsIndex[testPartsIndexIndex] = index;
              carry = false;
           } else {
              testPartsIndex[testPartsIndexIndex] = 0;
              carry = true;
           }
        }
        maxIndex &= (index == (part.length - 1));
     }
     return (!maxIndex);
   }

  /* This test is modeled after the testIsValid method described by the instructor. The method breaks up a set of test URLs into their 
   * four component parts and runs through all permutations and combinations of those parts, checking for errors */

   public void testIsValid(Object[] testObjects, long options) {
	      UrlValidator urlVal = new UrlValidator(null, null, options);
	      assertTrue(urlVal.isValid("http://www.google.com"));
	      assertTrue(urlVal.isValid("http://www.google.com/"));
	      int statusPerLine = 60;
	      int printed = 0;
	      if (printIndex)  {
	         statusPerLine = 6;
	      }
	      do {
	         StringBuffer testBuffer = new StringBuffer();
	         boolean expected = true;
	         for (int testPartsIndexIndex = 0; testPartsIndexIndex < testPartsIndex.length; ++testPartsIndexIndex) {
	            int index = testPartsIndex[testPartsIndexIndex];
	            ResultPair[] part = (ResultPair[]) testObjects[testPartsIndexIndex];
	            testBuffer.append(part[index].item);
	            expected &= part[index].valid;
	         }
	         //System.out.println(testPartsIndex[0]);
	         String url = testBuffer.toString();
	         boolean result = urlVal.isValid(url);
	         
	         if(result == true)
	        	 System.out.println(url);
	         assertEquals(url, expected, result);
	         
	         if (printStatus) {
	            if (printIndex) {
	               //System.out.print(testPartsIndextoString());
	            } else {
	               if (result == expected) {
	                  System.out.print('.');
	               } else {
	                  System.out.print('X');
	               }
	            }
	            printed++;
	            if (printed == statusPerLine) {
	               System.out.println();
	               printed = 0;
	            }
	         }
	      } while (incrementTestPartsIndex(testPartsIndex, testObjects));
	      if (printStatus) {
	         System.out.println();
	      }
   }
   

}
